package cmd

import (
	"bufio"
	"gitee.com/huanminabc/go-utils/vars"
	"io"
	"os"
	"strings"
	"time"
)

//func init() {
//	ReadStdinSustain()
//}

var ReadStdinStop = false

// ReadStdin注册器
var ReadStdinHandler = make(map[string]func(string))

// 注册ReadStdin
func RegisterReadStdin(name string, handler func(string)) {
	//判断是否已经注册
	if _, ok := ReadStdinHandler[name]; ok {
		panic("ReadStdinHandler: " + name + " 已经注册")
	}
	ReadStdinHandler[name] = handler
}

// 删除ReadStdin
func UnRegisterReadStdin(name string) {
	//判断是否已经注册
	if _, ok := ReadStdinHandler[name]; ok {
		delete(ReadStdinHandler, name)
	}
}

// 获取标准输入
// 注意: os.Stdin只能在main主程序中使用,不能通过单元测试调用,否则会无限的io.EOF
func ReadStdinSustain() {
	reader := bufio.NewReader(os.Stdin)
	go func() {

		for { //持续读取控制台输入
			for {
				input, _, err := reader.ReadLine() //这种方式读完不会有换行符
				//如果input不是nil,那么就执行
				if err == io.EOF {
					time.Sleep(100 * time.Millisecond)
					break
				}
				//判断如果是空
				if len(input) == 0 {
					continue
				}
				//通知所有注册的函数
				for _, fun := range ReadStdinHandler {
					go fun(string(input))
				}
			}

		}

	}()
}

// 获取标准输入,这种方式有一个bug,就是如果没有输入,那么就会一直等待,虽然有超时机制
// 但是等待的那个reader.ReadLine()还是会一直等待,直到有输入,这样如果在程序中有多个地方需要输入,那么就会出现问题
// 会被这个地方拦截到内容导致其他地方拿不到输入
func ReadStdin() string {
	// 创建一个带缓冲的通道来接收用户输入
	inputChan := make(chan string)
	stopChan := make(chan bool)
	var prePipeValue strings.Builder
	reader := bufio.NewReader(os.Stdin)
	// 启动一个goroutine来读取用户输入
	go func() {
		for {
			input, _, err := reader.ReadLine() //这种方式读完不会有换行符
			//如果reader是nil,那么就退出
			if reader == nil {
				//将数据从新写入到os.Stdin
				break
			}
			inputChan <- string(input)
			if err != nil { //读取到文件末尾
				stopChan <- true
				break
			}
		}
	}()

	//10微秒超时  ,之前设置的1毫秒太短了有时候会出现超时情况
	timerDuration := 5 * time.Millisecond
	timeout := time.NewTimer(timerDuration)
	defer timeout.Stop()
loop: //跳出多层循环
	for {
		timeout.Reset(timerDuration) //每次刷新重置
		select {
		case input := <-inputChan:
			prePipeValue.WriteString(input + vars.SystemLineBreak)
		case <-stopChan:
			// 退出
			break loop //读取到文件末尾
		case <-timeout.C: // 设置chan超时时间10ms
			// 超时了，没有接收到有命令输入
			//fmt.Println("超时了，没有接收到有命令输入")
			break loop //超时退出
		}
	}
	// 关闭channel
	close(inputChan)
	close(stopChan)
	reader = nil
	return prePipeValue.String()
}
